package com.roads.project.service.impl;

import com.roads.common.constant.Constants;
import com.roads.common.constant.UserConstants;
import com.roads.common.core.domain.entity.SysUser;
import com.roads.common.exception.ServiceException;
import com.roads.common.utils.BoqUtils;
import com.roads.common.utils.DateUtils;
import com.roads.common.utils.SecurityUtils;
import com.roads.common.utils.StringUtils;
import com.roads.project.domain.ProBoq;
import com.roads.project.domain.ProBoqMeterage;
import com.roads.project.domain.ProInstitution;
import com.roads.project.domain.ProInstitutionDetail;
import com.roads.project.mapper.ProBoqMapper;
import com.roads.project.mapper.ProBoqMeterageMapper;
import com.roads.project.mapper.ProInstitutionDetailMapper;
import com.roads.project.mapper.ProInstitutionMapper;
import com.roads.project.service.IProBoqService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 标段清单Service业务层处理
 * 
 * @author nhp
 * @date 2021-11-30
 */
@Service
public class ProBoqServiceImpl implements IProBoqService {

    @Autowired
    private ProBoqMapper proBoqMapper;

    @Autowired
    private ProBoqMeterageMapper meterageMapper;

    /**
     * 查询标段清单
     * 
     * @param id 标段清单主键
     * @return 标段清单
     */
    @Override
    public ProBoq selectProBoqById(Long id) {
        return proBoqMapper.selectProBoqById(id);
    }

    /**
     * 根据清单编号和机构编号查询清单
     *
     * @param institutionCode 机构编号
     * @param boqCode 清单编号
     * @return
     */
    @Override
    public ProBoq selectProBoqByCode(String institutionCode, String boqCode) {
        return proBoqMapper.selectProBoqByCode(institutionCode, boqCode);
    }

    @Override
    public String checkBoqCodeUnique(ProBoq proBoq) {
        Long id = StringUtils.isNull(proBoq.getId()) ? -1L : proBoq.getId();
        ProBoq search = proBoqMapper.selectProBoqByCode(proBoq.getInstitutionCode(), proBoq.getBoqCode());
        if (StringUtils.isNotNull(search) && !search.getId().equals(id)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 查询标段清单列表
     * 
     * @param proBoq 标段清单
     * @return 标段清单
     */
    @Override
    public List<ProBoq> selectProBoqList(ProBoq proBoq) {
        return proBoqMapper.selectProBoqList(proBoq);
    }

    /**
     * 根据标段编号和清单编号查询子节点
     *
     * @param institutionCode 标段编号
     * @param boqCode 清单编号
     * @return 标段工程量清单集合
     */
    @Override
    public List<ProBoq> selectChildrenList(String institutionCode, String boqCode) {
        return proBoqMapper.selectChildrenList(institutionCode, boqCode);
    }


    /**
     * 查询标段清单树形列表(名称=清单编号+清单名称)
     *
     * @param proBoq 标段清单
     * @return 标段清单集合
     */
    @Override
    public List<ProBoq> selectProBoqTreeList(ProBoq proBoq) {
        return proBoqMapper.selectProBoqTreeList(proBoq);
    }

    /**
     * 查询标段叶子节点清单列表(名称=清单编号+清单名称)
     *
     * @param proBoq 标段清单
     * @return 标段清单集合
     */
    @Override
    public List<ProBoq> selectLeafNodeList(ProBoq proBoq) {
        return proBoqMapper.selectLeafNodeList(proBoq);
    }

    /**
     * 查询标段清单大类列表（名称=清单编号+清单名称）
     * @param proBoq
     * @return
     */
    @Override
    public List<ProBoq> selectBigTypeList(ProBoq proBoq) {
        return proBoqMapper.selectBigTypeList(proBoq);
    }

    /**
     * 新增标段清单
     * 
     * @param proBoq 标段清单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertProBoq(ProBoq proBoq) {
        proBoq.setCreateTime(DateUtils.getNowDate());
        // 设置清单属性
        String parentCode = proBoq.getParentCode();
        String institutionCode = proBoq.getInstitutionCode();
        // 如果是根节点
        if (StringUtils.isEmpty(parentCode)) {
            proBoq.setLevel(1);
            proBoq.setAncestors(proBoq.getBoqCode());
        } else {
            // 查询父清单
            ProBoq parentBoq = proBoqMapper.selectProBoqByCode(institutionCode, parentCode);
            // 是否更新父清单
            if (Constants.YES.equals(parentBoq.getLeafNode())) {
                parentBoq.setLeafNode(Constants.NO);
                proBoqMapper.updateProBoq(parentBoq);
            }
            proBoq.setLevel(parentBoq.getLevel() + 1);
            proBoq.setAncestors(parentBoq.getAncestors() + "," + proBoq.getBoqCode());
        }
        // 设置标段清单编码
        proBoq.setInstitutionBoqCode(institutionCode + Constants.BOQ_SEPARATOR + proBoq.getBoqCode());
        proBoq.setLeafNode(Constants.YES);
        proBoqMapper.insertProBoq(proBoq);
        return 1;
    }

    /**
     * 修改标段清单
     *
     * @param oldBoq 修改前标段清单
     * @param proBoq 修改标段清单
     * @param meterageList 计量清单集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateProBoq(ProBoq oldBoq, ProBoq proBoq, List<ProBoqMeterage> meterageList) {
        // 处理工程量清单
        updateBoq(oldBoq, proBoq);
        // 处理计量清单
        updateMeterage(proBoq, meterageList);
        proBoqMapper.updateProBoq(proBoq);
        return 1;
    }

    private void updateBoq(ProBoq oldBoq, ProBoq proBoq) {
        int oldLevel = oldBoq.getLevel();
        // 新父项清单处理
        int oldParentLevel = 0;
        String nowAncestors = "";
        String oldAncestors = oldBoq.getAncestors();
        String oldParentCode = StringUtils.isEmpty(oldBoq.getParentCode()) ? "" : oldBoq.getParentCode();
        String nowParentCode = StringUtils.isEmpty(proBoq.getParentCode()) ? "" : proBoq.getParentCode();
        // 如果父项发生变化
        if (!oldParentCode.equals(nowParentCode)) {
            // 原父项清单处理
            if (!StringUtils.isEmpty(oldBoq.getParentCode())) {
                ProBoq oldParent = proBoqMapper.selectProBoqByCode(oldBoq.getInstitutionCode(), oldBoq.getParentCode());
                // 父项清单下是否有子节点
                int countOldChildren = proBoqMapper.countChildren(oldParent.getInstitutionCode(), oldParent.getBoqCode());
                if (countOldChildren == 1) {
                    oldParent.setLeafNode(Constants.YES);
                    proBoqMapper.updateProBoq(oldParent);
                }
            }

            if (!StringUtils.isEmpty(proBoq.getParentCode())) {
                ProBoq nowParent = proBoqMapper.selectProBoqByCode(proBoq.getInstitutionCode(), proBoq.getParentCode());
                oldParentLevel = nowParent.getLevel();
                if (Constants.YES.equals(nowParent.getLeafNode())) {
                    nowParent.setLeafNode(Constants.NO);
                    proBoqMapper.updateProBoq(nowParent);
                }
            }
        }
        // 计算级别差
        int level = oldParentLevel + 1;
        int dValue = level - oldLevel;
        if (oldParentCode.equals(nowParentCode)) {
            level = proBoq.getLevel();
            dValue = 0;
        }
        // 计算内码
        if (StringUtils.isEmpty(proBoq.getParentCode())) {
            nowAncestors = proBoq.getBoqCode();
        } else {
            ProBoq nowParent = proBoqMapper.selectProBoqByCode(proBoq.getInstitutionCode(), proBoq.getParentCode());
            nowAncestors = nowParent.getAncestors() + "," + proBoq.getBoqCode();
        }
        // 查询子清单
        List<ProBoq> childrenList = proBoqMapper.selectChildrenList(oldBoq.getInstitutionCode(), oldBoq.getBoqCode());
        if (childrenList.size() > 0) {
            for (ProBoq children : childrenList) {
                // 设置子节点的级别
                children.setLevel(children.getLevel() + dValue);
                children.setAncestors(children.getAncestors().replace(oldAncestors, nowAncestors));
                if (!proBoq.getBoqCode().equals(oldBoq.getBoqCode())) {
                    if (children.getParentCode().equals(oldBoq.getBoqCode())) {
                        children.setParentCode(proBoq.getBoqCode());
                    }
                }
                // 修改子节点下的祖籍列表
                ProBoqMeterage search = new ProBoqMeterage();
                search.setInstitutionCode(children.getInstitutionCode());
                search.setInstitutionBoqCode(children.getInstitutionBoqCode());
                List<ProBoqMeterage> meterageList = meterageMapper.selectModelList(search);
                for (ProBoqMeterage meterage : meterageList) {
                    meterage.setAncestors(children.getAncestors());
                    meterage.setUpdateBy(SecurityUtils.getUsername());
                    meterage.setUpdateTime(DateUtils.getNowDate());
                    meterageMapper.update(meterage);
                }
            }
            proBoqMapper.updateBatch(childrenList);
        }
        // 设置标段清单编码
        proBoq.setAncestors(nowAncestors);
        proBoq.setLevel(level);
        proBoq.setInstitutionBoqCode(proBoq.getInstitutionCode() + Constants.BOQ_SEPARATOR + proBoq.getBoqCode());
        proBoq.setUpdateTime(DateUtils.getNowDate());
    }

    private void updateMeterage(ProBoq proBoq, List<ProBoqMeterage> meterageList) {
        for (ProBoqMeterage meterage : meterageList) {
            meterage.setBoqName(proBoq.getBoqName());
            meterage.setAncestors(proBoq.getAncestors());
            meterage.setOrderNum(BigDecimal.valueOf(proBoq.getOrderNum()));
            meterage.setUnit(proBoq.getUnit());
            meterage.setPrice(proBoq.getPrice());
            meterage.setAmount(proBoq.getAmount());
            meterage.setUpdateBy(SecurityUtils.getUsername());
            meterage.setUpdateTime(DateUtils.getNowDate());
            meterageMapper.update(meterage);
        }
    }

    /**
     * 批量删除标段清单
     * 
     * @param ids 需要删除的标段清单主键
     * @return 结果
     */
    @Override
    public int deleteProBoqByIds(Long[] ids) {
        return proBoqMapper.deleteProBoqByIds(ids);
    }

    /**
     * 删除标段清单信息
     * 
     * @param id 标段清单主键
     * @return 结果
     */
    @Override
    public int deleteProBoqById(Long id) {
        return proBoqMapper.deleteProBoqById(id);
    }

    /**
     * 清空标段工程量清单
     *
     * @param institutionCode 标段编号
     */
    @Override
    public void clean(String institutionCode) {
        proBoqMapper.clean(institutionCode);
    }

    /**
     * 导入标段清单
     *
     * @param dataList 数据集合
     * @param userName 登录用户
     * @param institutionCode 机构编号
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importData(List<ProBoq> dataList, String userName, String institutionCode) {
        if (!StringUtils.isNotNull(dataList) || dataList.size() == 0) {
            return "导入数据不能为空！";
        }
        // 转map，方便获取
        Map<String, ProBoq> mapData = new HashMap<>(dataList.size());
        for (ProBoq proBoq : dataList) {
            mapData.put(proBoq.getBoqCode(), proBoq);
        }
        int successNum = 0;
        int failureNum = 0;
        int index = 2;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (ProBoq proBoq : dataList) {
            StringBuilder rowFailureMsg = new StringBuilder();
            try {
                String checkResult = validateData(proBoq, mapData);
                if (!StringUtils.isEmpty(checkResult)) {
                    StringUtils.appendFailureMsg(rowFailureMsg, index, checkResult);
                }
                // 设置清单
                proBoq.setInstitutionCode(institutionCode);
                proBoq.setInstitutionBoqCode(institutionCode + Constants.BOQ_SEPARATOR + proBoq.getBoqCode());
                proBoq.setCreateBy(userName);
                index++;
                if (!StringUtils.isEmpty(rowFailureMsg)) {
                    failureMsg.append(rowFailureMsg);
                    failureNum++;
                } else {
                    successNum++;
                }
            } catch (Exception e) {
                failureNum++;
                rowFailureMsg.append(StringUtils.appendFailureMsg(rowFailureMsg, index, e.getMessage()));
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            return failureMsg.toString();
        } else {
            proBoqMapper.insertBatch(dataList);
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条。");
        }
        return successMsg.toString();
    }

    /**
     *
     * @param proBoq
     * @param mapData
     * @return
     */
    private String validateData(ProBoq proBoq, Map<String, ProBoq> mapData) {
        // 清单编号
        String boqCode = proBoq.getBoqCode();
         if (StringUtils.isEmpty(boqCode)) {
            return "清单编码为空";
        }
        if (!BoqUtils.validateCompleteBoqCode(boqCode)) {
            return "清单编号格式不正确";
        }
        // 清单名称
        String boqName = proBoq.getBoqName();
        if (StringUtils.isEmpty(boqName)) {
            return "清单名称为空";
        }
        // 上级清单
        String parentCode = proBoq.getParentCode();
        if (!Constants.SUCCESS.equals(parentCode)) {
            ProBoq parent = mapData.get(parentCode);
            if (StringUtils.isNull(parent)) {
                return "上级清单未找到";
            }
        } else {
            proBoq.setParentCode(null);
        }
        // 祖籍列表
        String ancestors = proBoq.getAncestors();
        if (StringUtils.isEmpty(ancestors)) {
            return "祖籍列表不能为空";
        }
        if (!Constants.SUCCESS.equals(parentCode) && !ancestors.contains(parentCode)) {
            return "上级清单未在祖籍列表";
        }
        String[] ancestorArray = ancestors.split(",");
        for (int i = 0; i < ancestorArray.length; i++) {
            String p = ancestorArray[i];
            if (!Constants.SUCCESS.equals(p)) {
                ProBoq parent = mapData.get(p);
                if (StringUtils.isNull(parent)) {
                    return "祖籍列表里有父项清单不存在";
                }
            }
        }
        double orderNum = proBoq.getOrderNum();
        if (!StringUtils.isDouble(orderNum)) {
            return "显示顺序不正确";
        }
        if (!proBoq.getLevel().equals(ancestorArray.length)) {
            return "级别与祖籍列表不一致";
        }
        String leafNode = proBoq.getLeafNode();
        if (!Constants.YES.equals(leafNode) && !Constants.NO.equals(leafNode)) {
            return "是否叶节点不正确";
        }
//        if (Constants.YES.equals(leafNode)) {
//            if (!BoqUtils.validateValue(proBoq.getUnit(), proBoq.getAmount(), proBoq.getPrice(), proBoq.getTotal())) {
//                return "数据不完整，请检查单位、数量、单价、金额";
//            }
//        }
        return "";
    }

    /**
     * 工程量清单汇总
     *
     * @param institutionCode 机构编号
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int summary(String institutionCode) {
        // 取出标段的工程量清单
        ProBoq search = new ProBoq();
        search.setInstitutionCode(institutionCode);
        List<ProBoq> boqList = proBoqMapper.selectProBoqList(search);
        List<ProBoq> childrenSumList = proBoqMapper.sumListByInstitutionCode(institutionCode);
        // 转成map对象
        Map<String, ProBoq> sumMap = new HashMap<>(childrenSumList.size());
        for (ProBoq boq : childrenSumList) {
            sumMap.put(boq.getInstitutionBoqCode(), boq);
        }
        // 循环处理
        for (ProBoq boq: boqList) {
            if (Constants.YES.equals(boq.getLeafNode())) {
                String institutionBoqCode = boq.getInstitutionBoqCode();
                ProBoq sumBoq = sumMap.get(institutionBoqCode);
                if (StringUtils.isNotNull(sumBoq)) {
                    boq.setReviewAmount(sumBoq.getReviewAmount());
                    boq.setReviewTotal(sumBoq.getReviewTotal());
                    boq.setChangeAmount(sumBoq.getChangeAmount());
                    boq.setChangeTotal(sumBoq.getChangeTotal());
                }
            } else {
                String boqCode = boq.getBoqCode() + ",";
                BigDecimal amount = BigDecimal.valueOf(0);
                BigDecimal total = BigDecimal.valueOf(0);
                BigDecimal reviewAmount = BigDecimal.valueOf(0);
                BigDecimal reviewTotal = BigDecimal.valueOf(0);
                BigDecimal changeAmount = BigDecimal.valueOf(0);
                BigDecimal changeTotal = BigDecimal.valueOf(0);
                for (ProBoq sumBoq: childrenSumList) {
                    String ancestors = sumBoq.getAncestors();
                    if (ancestors.contains(boqCode)) {
                        if (sumBoq.getTotal() != null) {
                            total = total.add(sumBoq.getTotal());
                        }
                        if (sumBoq.getReviewTotal() != null) {
                            reviewTotal = reviewTotal.add(sumBoq.getReviewTotal());
                        }
                        if (sumBoq.getChangeTotal() != null) {
                            changeTotal = changeTotal.add(sumBoq.getChangeTotal());
                        }
                    }
                }
                boq.setAmount(amount.equals(BigDecimal.valueOf(0)) ? null : amount);
                boq.setTotal(total.equals(BigDecimal.valueOf(0)) ? null : total);
                boq.setReviewAmount(reviewAmount.equals(BigDecimal.valueOf(0)) ? null : reviewAmount);
                boq.setReviewTotal(reviewTotal.equals(BigDecimal.valueOf(0)) ? null : reviewTotal);
                boq.setChangeAmount(changeAmount.equals(BigDecimal.valueOf(0)) ? null : changeAmount);
                boq.setChangeTotal(changeTotal.equals(BigDecimal.valueOf(0)) ? null : changeTotal);
            }
        }
        proBoqMapper.updateBatch(boqList);
        return 1;
    }

    /**
     * 根据项目ID，用户查询变更金额
     *
     * @param projectId 项目id
     * @param user 用户
     * @param isAdmin 是否管理员
     * @return 变更金额
     */
    @Override
    public BigDecimal getChangeTotal(Integer projectId, SysUser user, boolean isAdmin) {
        BigDecimal changeTotal = BigDecimal.valueOf(0);
        if (isAdmin) {
            changeTotal = proBoqMapper.getChangeTotalByProjectId(projectId);
        } else {
            changeTotal = proBoqMapper.getChangeTotalByProjectIdAndUser(projectId, user.getUserName());
        }
        return changeTotal;
    }

}
